// StarDataWorker.js - 处理星表数据的Web Worker

// 光谱类型对应的颜色
const spectralColors = {
  'O': 0x9bb0ff,
  'B': 0xaabbff,
  'A': 0xd5eaff,
  'F': 0xfff4dd,
  'G': 0xffd1a1,
  'K': 0xffb366,
  'M': 0xff9966
};

// 简化的颜色索引映射
const colorMap = [
  0xaabbff,  // 0: 蓝色 (B型星)
  0xd5eaff,  // 1: 淡蓝色 (A型星)
  0xfff4dd,  // 2: 淡橙色 (F型星)
  0xffd1a1,  // 3: 橙色 (G型星)
  0xffb366,  // 4: 橙红色 (K型星)
  0xff9966   // 5: 红色 (M型星)
];

/**
 * 根据视星等计算星点大小
 * @param {number} magnitude - 视星等
 * @param {number} baseSize - 基础大小
 * @param {number} distance - 与相机的距离（用于LOD）
 * @returns {number} 计算后的大小
 */
function calculateStarSize(magnitude, baseSize = 1.0, distance = 100) {
  // 基于视星等的基础大小计算
  let size = baseSize * Math.pow(2, (-magnitude + 6) / 2.5);
  
  // LOD调整：根据距离调整大小
  // 远距离时，减小微小星星的大小，保持亮星的可见性
  if (distance > 150 && magnitude > 4.0) {
    size *= 0.8; // 远距离时减小暗星大小
  } else if (distance < 50) {
    size *= 1.2; // 近距离时略微增大星星大小
  }
  
  return Math.max(Math.min(size, 10.0), 0.1);
}

/**
 * 计算LOD级别
 * @param {number} distance - 与相机的距离
 * @returns {number} LOD级别（0-最高，3-最低）
 */
function calculateLODLevel(distance) {
  if (distance < 50) return 0; // 最高细节
  if (distance < 100) return 1; // 高细节
  if (distance < 200) return 2; // 中细节
  return 3; // 低细节
}

/**
 * 根据LOD级别过滤星星
 * @param {Array} stars - 星星数组
 * @param {number} lodLevel - LOD级别
 * @param {number} maxMagnitude - 最大星等
 * @returns {Array} 过滤后的星星数组
 */
function filterStarsByLOD(stars, lodLevel, maxMagnitude) {
  // 根据LOD级别调整可见星等阈值
  let effectiveMaxMagnitude = maxMagnitude;
  
  switch (lodLevel) {
    case 0: // 最高细节
      effectiveMaxMagnitude = Math.min(maxMagnitude, 8.0); // 显示更多暗星
      break;
    case 1: // 高细节
      effectiveMaxMagnitude = Math.min(maxMagnitude, 7.0);
      break;
    case 2: // 中细节
      effectiveMaxMagnitude = Math.min(maxMagnitude, 6.0);
      break;
    case 3: // 低细节
      effectiveMaxMagnitude = Math.min(maxMagnitude, 5.0); // 只显示亮星
      break;
  }
  
  // 过滤并按星等排序（亮星优先）
  return stars
    .filter(star => star.magnitude <= effectiveMaxMagnitude)
    .sort((a, b) => a.magnitude - b.magnitude);
}

/**
 * 赤道坐标转笛卡尔坐标
 * @param {number} ra - 赤经（度）
 * @param {number} dec - 赤纬（度）
 * @param {number} distance - 距离
 * @returns {object} 笛卡尔坐标 {x, y, z}
 */
function equatorialToCartesian(ra, dec, distance = 100) {
  const raRad = (ra / 180) * Math.PI;
  const decRad = (dec / 180) * Math.PI;
  const cosDec = Math.cos(decRad);
  
  const x = distance * cosDec * Math.cos(raRad);
  const y = distance * Math.sin(decRad);
  const z = distance * cosDec * Math.sin(raRad);
  
  return { x, y, z };
}

/**
 * 根据星等过滤星星
 * @param {Array} stars - 星表数据
 * @param {number} maxMagnitude - 最大可见星等
 * @returns {Array} 过滤后的星表数据
 */
function filterStarsByMagnitude(stars, maxMagnitude = 2.5) {
  return stars.filter(star => star.mag <= maxMagnitude);
}

/**
 * 从光谱类型提取主类型
 * @param {string} spectralClass - 光谱类型
 * @returns {string} 主光谱类型
 */
function getSpectralType(spectralClass) {
  if (!spectralClass) return 'Unknown';
  return spectralClass.charAt(0).toUpperCase();
}

/**
 * 计算恒星闪烁因子
 * @param {number} baseFactor - 基础闪烁因子
 * @returns {number} 闪烁因子
 */
function calculateTwinkleFactor(baseFactor = 0.05) {
  return 1.0 + (Math.random() - 0.5) * baseFactor;
}

/**
 * 计算点是否在视锥体内
 * @param {Object} point - 点坐标 {x, y, z}
 * @param {Array} viewMatrix - 视图矩阵
 * @param {Array} projectionMatrix - 投影矩阵
 * @returns {boolean} 是否在视锥体内
 */
function isPointInFrustum(point, viewMatrix, projectionMatrix) {
  // 转换为齐次坐标
  const pos = {
    x: point.x,
    y: point.y,
    z: point.z,
    w: 1
  };
  
  // 应用视图矩阵
  const viewX = pos.x * viewMatrix[0] + pos.y * viewMatrix[4] + pos.z * viewMatrix[8] + pos.w * viewMatrix[12];
  const viewY = pos.x * viewMatrix[1] + pos.y * viewMatrix[5] + pos.z * viewMatrix[9] + pos.w * viewMatrix[13];
  const viewZ = pos.x * viewMatrix[2] + pos.y * viewMatrix[6] + pos.z * viewMatrix[10] + pos.w * viewMatrix[14];
  const viewW = pos.x * viewMatrix[3] + pos.y * viewMatrix[7] + pos.z * viewMatrix[11] + pos.w * viewMatrix[15];
  
  // 应用投影矩阵
  const clipX = viewX * projectionMatrix[0] + viewY * projectionMatrix[4] + viewZ * projectionMatrix[8] + viewW * projectionMatrix[12];
  const clipY = viewX * projectionMatrix[1] + viewY * projectionMatrix[5] + viewZ * projectionMatrix[9] + viewW * projectionMatrix[13];
  const clipZ = viewX * projectionMatrix[2] + viewY * projectionMatrix[6] + viewZ * projectionMatrix[10] + viewW * projectionMatrix[14];
  const clipW = viewX * projectionMatrix[3] + viewY * projectionMatrix[7] + viewZ * projectionMatrix[11] + viewW * projectionMatrix[15];
  
  // 标准化设备坐标
  if (clipW === 0) return false;
  
  const ndcX = clipX / clipW;
  const ndcY = clipY / clipW;
  const ndcZ = clipZ / clipW;
  
  // 检查是否在 [-1, 1] 范围内
  return ndcX >= -1 && ndcX <= 1 && 
         ndcY >= -1 && ndcY <= 1 && 
         ndcZ >= -1 && ndcZ <= 1;
}

/**
 * 快速检查点是否在视锥体范围内（使用简化的边界球检查）
 * @param {Object} point - 点坐标 {x, y, z}
 * @param {Object} cameraPosition - 相机位置 {x, y, z}
 * @returns {boolean} 是否可见
 */
function isPointVisibleQuick(point, cameraPosition) {
  // 计算从相机到点的向量
  const dx = point.x - cameraPosition.x;
  const dy = point.y - cameraPosition.y;
  const dz = point.z - cameraPosition.z;
  
  // 快速剔除：点在相机后方
  const dotProduct = dx * cameraPosition.x + dy * cameraPosition.y + dz * cameraPosition.z;
  
  return dotProduct > 0;
}

/**
 * 处理星表数据，生成Three.js所需的几何体数据（支持渐进式加载和视锥体剔除）
 * @param {Array} stars - 原始星表数据
 * @param {Object} options - 处理选项
 * @returns {Object} 处理后的星表几何体数据
 */
function processStarData(stars, options = {}) {
  const { 
    maxMagnitude = 2.5, 
    magnitudeScale = 1.0, 
    distance = 100,
    viewMatrix = null,
    projectionMatrix = null,
    cameraPosition = null,
    batchSize = 1000,
    batchIndex = 0,
    useFrustumCulling = false,
    useLOD = true,
    cameraDistance = 100 // 用于LOD计算的相机距离
  } = options;
  
  // 计算LOD级别
  const lodLevel = useLOD ? calculateLODLevel(cameraDistance) : 0;
  
  // 根据LOD级别过滤星星
  let filteredStars = useLOD 
    ? filterStarsByLOD(stars, lodLevel, maxMagnitude)
    : filterStarsByMagnitude(stars, maxMagnitude).sort((a, b) => a.magnitude - b.magnitude);
  
  // 应用视锥体剔除（如果提供了矩阵）
  if (useFrustumCulling) {
    filteredStars = filteredStars.filter(star => {
      const pos = equatorialToCartesian(star.ra, star.dec, distance);
      
      if (viewMatrix && projectionMatrix) {
        return isPointInFrustum(pos, viewMatrix, projectionMatrix);
      } else if (cameraPosition) {
        // 使用简化检查
        return isPointVisibleQuick(pos, cameraPosition);
      }
      return true;
    });
  }
  
  // 实现分批加载
  const startIndex = batchIndex * batchSize;
  const endIndex = startIndex + batchSize;
  const batchStars = filteredStars.slice(startIndex, endIndex);
  
  const positions = [];
  const colors = [];
  const sizes = [];
  const metadata = [];
  
  // 为每颗恒星生成位置、颜色和大小
  batchStars.forEach(star => {
    const pos = equatorialToCartesian(star.ra, star.dec, distance);
    
    positions.push(pos.x, pos.y, pos.z);
    
    // 使用光谱类型对应的颜色
    const spectralType = star.spectral ? star.spectral.charAt(0) : 'Default';
    const colorIndex = star.colorIdx !== undefined ? star.colorIdx : 3;
    const color = colorMap[colorIndex] || 0xffffff;
    
    // 转换为RGB分量
    const r = ((color >> 16) & 0xff) / 255;
    const g = ((color >> 8) & 0xff) / 255;
    const b = (color & 0xff) / 255;
    
    colors.push(r, g, b);
    
    // 根据视星等计算大小（考虑LOD）
    sizes.push(calculateStarSize(star.magnitude, magnitudeScale, cameraDistance));
    
    // 存储元数据
    metadata.push({
      id: star.id,
      name: star.name,
      magnitude: star.magnitude,
      spectral: star.spectral,
      position: pos,
      ra: star.ra,
      dec: star.dec,
      detailLevel: lodLevel // 记录当前星星的细节级别
    });
  });
  
  return {
    positions: new Float32Array(positions),
    colors: new Float32Array(colors),
    sizes: new Float32Array(sizes),
    metadata: metadata,
    count: batchStars.length,
    totalCount: filteredStars.length,
    remainingCount: filteredStars.length - endIndex,
    isComplete: endIndex >= filteredStars.length,
    batchIndex: batchIndex + 1,
    lodLevel // 返回当前使用的LOD级别
  };
}

/**
 * 计算星座连线数据（支持视锥体剔除）
 * @param {Array} stars - 星表数据
 * @param {Object} constellationLines - 星座连线定义
 * @param {Object} options - 处理选项
 * @returns {Array} 处理后的星座连线数据
 */
function processConstellationData(stars, constellationLines, options = {}) {
  const { 
    distance = 100, 
    viewMatrix = null, 
    projectionMatrix = null,
    useFrustumCulling = false,
    visibleConstellations = null
  } = options;
  
  const starMap = new Map();
  stars.forEach(star => {
    starMap.set(star.id, star);
  });
  
  const constellationsData = [];
  
  // 如果指定了可见星座，只处理这些星座
  const constellationsToProcess = visibleConstellations 
    ? visibleConstellations 
    : Object.keys(constellationLines);
  
  constellationsToProcess.forEach(constellationName => {
    const linePairs = constellationLines[constellationName];
    if (!linePairs) return;
    
    const lines = [];
    
    linePairs.forEach(pair => {
      const star1 = starMap.get(pair[0]);
      const star2 = starMap.get(pair[1]);
      
      if (star1 && star2) {
        const pos1 = equatorialToCartesian(star1.ra, star1.dec, distance);
        const pos2 = equatorialToCartesian(star2.ra, star2.dec, distance);
        
        // 视锥体剔除（如果启用）
        if (useFrustumCulling && viewMatrix && projectionMatrix) {
          // 如果线段的两个端点都不可见，则跳过该线段
          if (!isPointInFrustum(pos1, viewMatrix, projectionMatrix) && 
              !isPointInFrustum(pos2, viewMatrix, projectionMatrix)) {
            return;
          }
        }
        
        lines.push([pos1, pos2]);
      }
    });
    
    if (lines.length > 0) {
      constellationsData.push({
        name: constellationName,
        lines: lines
      });
    }
  });
  
  return constellationsData;
}

/**
 * 计算星座中心点坐标
 * @param {Array} constellations - 星座数据
 * @param {string} constellationName - 星座名称
 * @param {number} scale - 缩放因子
 * @returns {Object} 中心点坐标 {x, y, z}
 */
function calculateConstellationCenter(constellations, constellationName, scale = 100) {
  const constellation = constellations.find(c => c.name === constellationName);
  if (!constellation) return { x: 0, y: 0, z: 0 };
  
  return equatorialToCartesian(constellation.ra, constellation.dec, scale * 0.9);
}

/**
 * 处理银河粒子数据（支持视锥体剔除和分批加载）
 * @param {number} particleCount - 粒子数量
 * @param {Object} options - 配置选项
 * @returns {Object} 银河粒子数据
 */
function generateMilkyWayParticles(particleCount = 2000, options = {}) {
  const { 
    radius = 500, 
    height = 100, 
    densityPower = 1.5,
    viewMatrix = null,
    projectionMatrix = null,
    batchSize = 1000,
    batchIndex = 0,
    useFrustumCulling = false
  } = options;
  
  // 计算批次信息
  const totalBatches = Math.ceil(particleCount / batchSize);
  const startIndex = batchIndex * batchSize;
  const endIndex = Math.min((batchIndex + 1) * batchSize, particleCount);
  
  // 粒子位置数组
  const positions = [];
  
  for (let i = startIndex; i < endIndex; i++) {
    // 使用固定种子确保同一批次生成相同的粒子
    const seed = i * 100001 + 12345;
    const rnd1 = (seed % 1000) / 1000;
    const rnd2 = ((seed + 1234) % 1000) / 1000;
    const rnd3 = ((seed + 5678) % 1000) / 1000;
    
    // 在银河平面上随机分布，但更集中在中心区域
    const angle = rnd1 * Math.PI * 2;
    const r = Math.pow(rnd2, densityPower) * radius;
    const y = (rnd3 - 0.5) * height;
    
    // 计算位置
    const x = Math.cos(angle) * r;
    const z = Math.sin(angle) * r - 499.9; // 略高于银河平面
    
    const position = { x, y, z };
    
    // 视锥体剔除（如果启用）
    if (useFrustumCulling && viewMatrix && projectionMatrix) {
      if (!isPointInFrustum(position, viewMatrix, projectionMatrix)) {
        continue;
      }
    }
    
    positions.push(x, y, z);
  }
  
  return {
    positions: new Float32Array(positions),
    count: positions.length / 3,
    totalCount: particleCount,
    remainingCount: particleCount - endIndex,
    isComplete: batchIndex >= totalBatches - 1,
    batchIndex: batchIndex + 1
  };
}

// 监听主线程消息
self.onmessage = function(e) {
  const { action, data, options } = e.data;
  
  try {
    let result;
    
    switch (action) {
      case 'PROCESS_STARS':
        result = processStarData(data.stars, options);
        break;
        
      case 'PROCESS_CONSTELLATIONS':
        result = processConstellationData(data.stars, data.constellationLines, options?.distance);
        break;
        
      case 'CALCULATE_CONSTELLATION_CENTER':
        result = calculateConstellationCenter(data.constellations, data.constellationName, options?.scale);
        break;
        
      case 'GENERATE_MILKY_WAY_PARTICLES':
        result = generateMilkyWayParticles(data.particleCount, options);
        break;
        
      case 'CALCULATE_TWINKLE_FACTOR':
        result = calculateTwinkleFactor(options?.baseFactor);
        break;
        
      default:
        throw new Error(`未知的操作: ${action}`);
    }
    
    // 发送结果回主线程
    self.postMessage({
      success: true,
      action: action,
      result: result
    });
  } catch (error) {
    // 发送错误信息回主线程
    self.postMessage({
      success: false,
      action: action,
      error: error.message
    });
  }
};

// 初始化完成通知
self.postMessage({
  success: true,
  action: 'INITIALIZED',
  result: 'StarDataWorker 已初始化'
});